package.cpath = "/usr/nginx/?.so;;"
local json = require 'cjson'
local require = require
local setmetatable = setmetatable
local error = error
local table = table
local ngx = ngx
local pcall = pcall
local os = os
local string = string
local tonumber = tonumber
package.cpath = "/usr/nginx/?.so;;"
local json = require 'cjson'
package.cpath = "/usr/nginx/jieyan-backend-production/?.so;;"
package.path = "/usr/nginx/jieyan-backend-production/?.lua;;"
local redis = require "redis"
local server = require "modules.server"
package.cpath = "/opt/xyitech/jieyan-backend-production/xbit/?.so"
local xbit = require 'xbit'
local channel_name = "jieyan"

 _int32_t = 0
 _int16_t = 1
 _float = 2
 _uint32_t = 4
 _uint16_t = 5
 _uint8_t = 6
 _int8_t = 7

--create connection
local sock = ngx.req.socket(true)

local fid = nil

local subscribed = false
--create success
if not sock then
  ngx.log(ngx.ERR, "failed to new tcp socket: ", err)
  return ngx.exit(444)
end
 
 
local push = function()
    -- --create redis
    local red = redis:new()
    red:set_timeout(5000) -- 1 sec
    local ok, err = red:connect("127.0.0.1", 6379)
    if not ok then
        ngx.log(ngx.ERR, "failed to connect redis: ", err)
        sock:send_close()
        return
    end
 
    --sub
    -- local res, err = red:subscribe(channel_name)
    -- if not res then
    --     ngx.log(ngx.ERR, "failed to sub redis: ", err)
    --     sock:send_close()
    --     return
    -- end

    local res, err = red:subscribe("fs_update")
    if not res then
        ngx.log(ngx.ERR, "failed to sub redis: ", err)
        sock:send_close()
        return
    end
    local buff = nil

    -- loop : read from redis
    while true do
        local res, err = red:read_reply()
        if res then
            local data = res[3]
            -- TODO do data here
            --
            if not sock then
                ngx.log(ngx.ERR, "lost sockect")
                return ngx.exit(444)
            end
            if buff then
                buff = buff .. data
            else 
                buff = data
            end
            local len = xbit.readBuff(_uint32_t, buff, 0)
            ngx.log(ngx.ERR, len)
            ngx.log(ngx.ERR, #buff)
            while #buff > 4 and #buff >= len do
                data = string.sub(buff, 1, len)
                
            -- end
            -- ngx.log(ngx.ERR, json.encode(res))
            ngx.log(ngx.ERR, data)
            ngx.log(ngx.ERR, #data)
            -- sock:settimeout(1000)  -- one second timeout
                data = filterData(fid, data)
                if data then
                    ngx.log(ngx.ERR, data)
                    ngx.log(ngx.ERR, #data)
                    local bytes, err = sock:send(data)
                    if not bytes then
                        -- better error handling
                        ngx.log(ngx.ERR, "failed to send text: ", err)
                        return ngx.exit(444)
                    end
                    ngx.log(ngx.ERR, bytes)
                end
                buff = string.sub(buff, 1 + len)
            end

        else
            if err ~= "timeout" then
                ngx.log(ngx.ERR, "Redis read error: ", err)
                return ngx.exit(444)
            end
        end
    end
end

 function filterData(fid, data)
    ngx.log(ngx.ERR, data)

    local body = json.decode(string.sub(data, 5, len))
    
    local _fid = tonumber(body.id)
    local msgSet = tonumber(body["msg set"])
    local msgId = tonumber(body["msg id"])
    ngx.log(ngx.ERR, _fid)
    ngx.log(ngx.ERR, fid)
    ngx.log(ngx.ERR, fid == _fid)
    if fid and fid == _fid then
        return data
    elseif msgSet == 0 and msgId == 8 then
        return data
    else
        return nil
    end
end
 
local co = ngx.thread.spawn(push)

local red_set = redis:new()
red_set:set_timeout(1000) -- 1 sec
local ok, err = red_set:connect("127.0.0.1", 6379)
if not ok then
    ngx.log(ngx.ERR, "failed to connect redis: ", err)
end

local red_p = redis:new()
red_p:set_timeout(1000) -- 1 sec
local ok, err = red_p:connect("127.0.0.1", 6379)
if not ok then
    ngx.log(ngx.ERR, "failed to connect redis: ", err)
end

local buff = nil
local readSize = 4
--main loop
while true do
    -- 获取数据
    if not sock then
        ngx.log(ngx.ERR, "sock not found")
    end
    -- sock:settimeout(5000)  -- one second timeout
    local data, err, partial = sock:receive(readSize)
    -- 如果连接损坏 退出
    if err and err ~= "timeout" then
        -- ngx.log(ngx.ERR, "partial", partial)
        ngx.log(ngx.ERR, "sock error:", err)
        return ngx.exit(444)
    end
    if data then
        if buff then
            buff = buff .. data
        else 
            buff = data
        end
        local totalLen = xbit.readBuff(_uint32_t, buff, 0) 
        while #buff > 4 and #buff >= totalLen + 4 do
            local len = xbit.readBuff(_uint32_t, buff, 0)
            -- ngx.log(ngx.ERR, "len" .. len)

            if len > 2 then
                local body = string.sub(buff, 5, len)
                local ok, res = pcall(json.encode, body)
                if not ok then
                    ngx.log(ngx.ERR, "wrong data ", body)
                    break
                end

                -- ngx.log(ngx.ERR, body)
                if not fid then
                    fid = tonumber(json.decode(body).id)
                end
                -- ngx.log(ngx.ERR, json.decode(body).id)
                -- ngx.log(ngx.ERR, "body is" .. #body)
                local res, err = red_p:publish("ws_update", body)
                if not res then
                    ngx.log(ngx.ERR, "failed to publish redis: ", err)
                end
            end
            buff = string.sub(buff, len + 1)
            -- ngx.log(ngx.ERR, "buff is" .. #buff)
        end
    end 
end
ngx.log(ngx.ERR, "socket closing3")
sock:send_close()
ngx.thread.wait(co)